#pragma once
#include <iostream>
#include <cstring>
#include <cerrno>
#include <memory>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
using namespace std;

const string SEM_KEY_PATH = "/tmp";
const int SEM_KEY_ID = 0x6666;
const int SEM_NUM = 1;
#define SEM_FLAG_BUID   (IPC_EXCL | IPC_CREAT | 0666)
#define SEM_FLAG_GET    IPC_CREAT

class Semaphore 
{
private:
    void PV(int op)
    {
        struct sembuf sb;
        sb.sem_num = 0; //操作第0个信号量
        sb.sem_op = op; //操作数
        sb.sem_flg = SEM_UNDO;//操作标志
       // cout<<"sem_op = " << sb.sem_op << endl;
        if(semop(_semid,&sb,1) == -1)
        {
            cerr << "semop error: " << strerror(errno) << endl;
        }
       // cout<<"semop success!"<<endl;
    }
public:
    Semaphore(int semid):_semid(semid)
    {
    }
    ~Semaphore()
    {
        if(_semid >= 0)
        {
            //删除信号量
            if(semctl(_semid,0,IPC_RMID) == -1)
            {
                cerr << "semctl IPC_RMID error: " 
                     << strerror(errno) << endl;
            }

        }
    }

    void P() // Wait operation
    {
        PV(-1);
    }
    void V()
    {
        PV(1);
    }

private:
    int _semid;
};

class SemBuider
{
    private:
    void Init(int semid, int num)
    {
        union semun
        {
            int val;                // Value for SETVAL
            struct semid_ds *buf;   // Buffer for IPC_STAT, IPC_SET
            unsigned short *array;  // Array for GETALL, SETALL
            struct seminfo *__buf;  // Buffer for IPC_INFO
        }su;
        su.val = _val; // Initialize semaphore to 1
        for(int i = 0; i < num; i++) {
            if(semctl(semid, i, SETVAL, su) == -1)
            {
                cerr << "semctl error for semaphore " << i 
                     << ": " << strerror(errno) << endl;
            }
        }
    }
    string int2Hex(int num)
    {
        char buf[20];
        snprintf(buf, sizeof(buf), "0x%X", num);
        return string(buf);
    }
    public:
    SemBuider() {}
    ~SemBuider() {}
    SemBuider setVal(int val)
    {
        // This function can be expanded to set initial values if needed
        _val = val;
        return *this;
    }
    shared_ptr<Semaphore> buid(int flag,int num = SEM_NUM)
    {
        //1.获取key
        key_t key = ftok(SEM_KEY_PATH.c_str(), SEM_KEY_ID);
        if (key == -1)
        {
            cerr << "ftok error" << endl;
            return nullptr;
        }
        cout<<"key = " << int2Hex(key) << endl;
        //2.创建/获取信号量
        int semid = semget(key,num,flag);
        if(semid == -1)
        {   
            cerr << "semget error" << endl;
            return nullptr;
        }
        cout<<"semid = " << semid << endl;
        //3.初始化信号量
        if(flag == SEM_FLAG_BUID)
        {
            Init(semid,num);
        }
        //4.创建并返回信号量对象
        return make_shared<Semaphore>(semid);
    }
    private:
    int _val;
};